﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;


namespace mat2tab_fun
{
    class MyPlot
    {
        List<Point> fun = new List<Point>(); //Punkty otrzymanej funckji
        public List<Line> aproxfun = new List<Line>(); //Punkty wynikowej funckji

        Double n, m;

        List<Double> s = new List<Double>(); // wspolczynnik s,t do wyliczenia aproksymacji
        List<Double> t = new List<Double>();
        public Double[] a; // wspolczynniki wynikowego rownania

        public MyPlot(List<Line> lines, Double rzad)
        {
            this.m = rzad;
            this.n = lines.Count;
            this.a = new Double[(int)m];
            foreach (Line l in lines)
            {
                fun.Add(new Point(l.X1, l.Y1));
                fun.Add(new Point(l.X1, l.Y1));
            }
                        
        }

        public void Draw(int rzad)
        {
            aproxfun.Clear();
            if(rzad == 3)
                for (int i = 0; i < 1000; i+=10)
                {
                    Line l = new Line();
                    l.X1 = i;
                    l.Y1 = a[0] + a[1] * i + a[2] * i * i;
                    l.X2 = i + 10;
                    l.Y2 = a[0] + a[1] * (i + 10) + a[2] * (i + 10) * (i + 10);
                    //aproxfun.Add(new Point(i, a[0] + a[1]*i));

                    aproxfun.Add(l);
                }
            else if (rzad == 2)
                for (int i = 0; i < 1000; i += 10)
                {
                    Line l = new Line();
                    l.X1 = i;
                    l.Y1 = a[0] + a[1] * i;
                    l.X2 = i + 10;
                    l.Y2 = a[0] + a[1] * (i + 10);
                    //aproxfun.Add(new Point(i, a[0] + a[1]*i));

                    aproxfun.Add(l);
                }
        }

        public void Draw(double a, double b, double c)
        {
            aproxfun.Clear();
                for (int i = 0; i < 1000; i+=10)
                {
                    Line l = new Line();
                    l.X1 = i;
                    l.Y1 = c + b * i + a * i * i;
                    l.X2 = i + 10;
                    l.Y2 =c + b * (i + 10) +a * (i + 10) * (i + 10);

                    aproxfun.Add(l);
                }
        }


        public void Approx()
        {
            for(int i = 0; i <= 2*m; i++)
		    {
                s.Add(0);
                if (i <= m)
                    t.Add(0);
			    for(int j = 0 ; j<n; j++)
			    {
				    s[i] += Math.Pow(fun[j].X, i);
				    if(i <= m)
                        t[i] += fun[j].Y * Math.Pow(fun[j].X, i);
			    }
		    }

            Double[,] A = new Double[(int)m + 1, (int)m + 2];
            Double[] b = new Double[(int)m+1];

            for (int i = 0; i < m+1; i++)
            {
                for (int j = 0, k = i; j < m+1; j++, k++)
                    A[i, j] = s[k];
                b[i] = t[i];
            }

            a = GaussaSeidela(A, b, (int)m, 0.000000000000000000000001);


            Draw((int)m);


        }

        private double[] GaussaSeidela(double[,] A, double[] b, int n, double eps)
        {
            double tmp1;
            double tmp2;
            double[] x = new double[n];
            double[] x1 = new double[n];
            double sumx, sumx1;
            int count = 0;
            for (int i = 0; i < n; i++)
            {
                x1[i] = b[i] / A[i, i];
            }

            do
            {
                for (int i = 0; i < n; i++)
                {
                    x[i] = x1[i];
                }

                for (int i = 0; i < n; i++)
                {
                    tmp1 = 0;
                    tmp2 = 0;
                    for (int j = 0; j < i; j++)
                    {
                        tmp1 += A[i, j] * x1[j];
                    }
                    for (int j = i + 1; j < n; j++)
                    {
                        tmp2 += A[i, j] * x[j];
                    }
                    x1[i] = (1.0 / A[i, i]) * (b[i] - tmp1 - tmp2);
                }

                sumx = 0;
                sumx1 = 0;
                for (int i = 0; i < n; i++)
                {
                    sumx += x[i];
                    sumx1 += x1[i];
                }

                ++count;
            } while (Math.Abs(sumx - sumx1) > eps);

            return x1;
        }

    }
}
